package pers.xiaojun.boot.tenant.config;

import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import pers.xiaojun.boot.common.biz.system.tenant.TenantCommonApi;
import pers.xiaojun.boot.common.constants.WebFilterOrderConstants;
import pers.xiaojun.boot.mybatis.core.util.MyBatisUtils;
import pers.xiaojun.boot.tenant.config.properties.TenantProperties;
import pers.xiaojun.boot.tenant.core.annotation.TenantIgnore;
import pers.xiaojun.boot.tenant.core.db.TenantDatabaseInterceptor;
import pers.xiaojun.boot.tenant.core.security.TenantSecurityFilter;
import pers.xiaojun.boot.tenant.core.service.TenantCommonService;
import pers.xiaojun.boot.tenant.core.service.TenantCommonServiceImpl;
import pers.xiaojun.boot.tenant.core.web.TenantContextWebFilter;
import pers.xiaojun.boot.web.config.properties.WebProperties;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 租户配置类
 * <p>
 * 当 xiaojun.tenant.enable = true 时，自动配置
 *
 * @author xiaojun
 * @since 2025-11-22
 */
//@AutoConfiguration
@EnableConfigurationProperties(TenantProperties.class)
@RequiredArgsConstructor
@ConditionalOnProperty(prefix = "xiaojun.tenant", value = "enable", matchIfMissing = true)
public class TenantAutoConfiguration {

    private final TenantProperties tenantProperties;


    @Bean
    public TenantCommonService tenantCommonService(TenantCommonApi tenantCommonApi) {
        return new TenantCommonServiceImpl(tenantCommonApi);
    }

    /**
     * 添加租户Web过滤器
     * <p>
     * 用于从请求头中获取租户编号，并存入 TenantContext 中
     *
     * @return Web过滤器
     */
    @Bean
    public FilterRegistrationBean<TenantContextWebFilter> tenantContextWebFilter(RequestMappingHandlerMapping requestMapping) {
        FilterRegistrationBean<TenantContextWebFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new TenantContextWebFilter(tenantProperties));
        registrationBean.setOrder(WebFilterOrderConstants.TENANT_CONTEXT_FILTER);
        tenantProperties.getIgnoreUrls().addAll(getTenantIgnoreUrls(requestMapping));
        return registrationBean;
    }

    /**
     * 添加租户安全过滤器
     * <p>
     * 用于校验租户是否可用，以及是否匹配
     *
     * @param webProperties       web配置
     * @param tenantCommonService 租户服务
     * @return Web过滤器
     */
    @Bean
    public FilterRegistrationBean<TenantSecurityFilter> tenantSecurityFilter(WebProperties webProperties, TenantCommonService tenantCommonService) {
        FilterRegistrationBean<TenantSecurityFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new TenantSecurityFilter(webProperties, tenantProperties, tenantCommonService));
        registrationBean.setOrder(WebFilterOrderConstants.TENANT_SECURITY_FILTER);
        return registrationBean;
    }


    /**
     * 将租户处理器注入MyBatisPlus插件
     *
     * @param interceptor MyBatisPlus 拦截器对象
     * @return 租户拦截器插件
     */
    @Bean
    public TenantLineInnerInterceptor tenantLineInnerInterceptor(MybatisPlusInterceptor interceptor) {
        TenantLineInnerInterceptor inner = new TenantLineInnerInterceptor(new TenantDatabaseInterceptor(tenantProperties));
        MyBatisUtils.addInnerInterceptor(interceptor, inner, 0);
        return inner;
    }

    /**
     * 获取接口方法中带有 @TenantIgnore 的路径
     *
     * @param requestMapping 请求映射对象
     * @return 忽略租户的路径
     */
    private Set<String> getTenantIgnoreUrls(RequestMappingHandlerMapping requestMapping) {
        HashSet<String> ignoreUrls = new HashSet<>();
        Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestMapping.getHandlerMethods();

        handlerMethods.forEach((requestInfo, method) -> {
            if (method.hasMethodAnnotation(TenantIgnore.class) && requestInfo.getPathPatternsCondition() != null) {
                ignoreUrls.addAll(requestInfo.getPathPatternsCondition().getPatternValues());
            }
        });
        return ignoreUrls;
    }


}
